#!/bin/bash
# PHP CodeSniffer pre-commit hook for git
readonly COMMIT_INTRODUCING_PSR2='7bf3932edde43583f4a5889e76896c3cdfe5444b'
readonly TMP_STAGING_DIR=$(mktemp -d)

cleanup_temporary_directory() {
    rm -rf "${TMP_STAGING_DIR}"
}
trap cleanup_temporary_directory EXIT

get_list_of_files() {
    git diff --cached --name-only --diff-filter=ACMRTUXB | grep \.php$
}

get_initial_commit() {
    local file=$1
    git log --diff-filter=A --format=format:%H "${file}" | tail -1
}

get_reference_source_file() {
    local file=$1
    git diff-index --cached HEAD ${file} | cut -d ' ' -f4
}

copy_staged_file_to_temporary_directory() {
    local file=$1
    local reference=$2
    mkdir -p "$TMP_STAGING_DIR/$(dirname ${file})"
    git cat-file blob ${reference} > "${TMP_STAGING_DIR}/${file}"
    echo "${TMP_STAGING_DIR}/${file}"
}

is_file_more_recent_than_psr2_coding_rule() {
    local file=$1
    local initial_file_commit
    initial_file_commit=$(get_initial_commit "${file}")
    if [ -z "${initial_file_commit}" ]
    then
        echo 1
    else
        git merge-base --is-ancestor "${initial_file_commit}" ${COMMIT_INTRODUCING_PSR2}
        echo $?
    fi
}

get_list_of_mandatory_psr2_files() {
    local files=$1
    local file

    for file in ${files}
    do
        if [ "$(is_file_more_recent_than_psr2_coding_rule "${file}")" -ne 0 ]
        then
            local reference_file=$(get_reference_source_file "${file}")
            copy_staged_file_to_temporary_directory ${file} ${reference_file}
        fi
    done
}

main() {
    local files_list
    files_list=$(get_list_of_files)
    local files_psr2_mandatory
    files_psr2_mandatory=$(get_list_of_mandatory_psr2_files "${files_list}")
    if [[ -n ${files_psr2_mandatory} ]]
    then
        local phpcs_output
        phpcs_output=$(./src/vendor/bin/phpcs --standard=PSR2 --encoding=utf-8 --warning-severity=0 -p ${files_psr2_mandatory})
        local status=$?
        if [ ${status} -ne 0 ]
        then
            echo "$phpcs_output" | less
        fi

        cleanup_temporary_directory
        exit ${status}
    fi
}
main